package com.datagateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 内存泄漏检测器
 * 负责检测和分析内存泄漏问题
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class MemoryLeakDetector {

    private static final Logger logger = LoggerFactory.getLogger(MemoryLeakDetector.class);

    @Autowired
    private AlertManager alertManager;

    @Autowired
    private SystemMonitor systemMonitor;

    /**
     * 内存使用历史记录
     */
    private final ConcurrentHashMap<Long, MemorySnapshot> memoryHistory = new ConcurrentHashMap<>();

    /**
     * 内存泄漏检测配置
     */
    private static final int HISTORY_SIZE = 20; // 保留20个历史记录
    private static final long DETECTION_INTERVAL = 60000; // 1分钟检测一次
    private static final double LEAK_THRESHOLD = 10.0; // 10%增长视为潜在泄漏
    private static final int MIN_SAMPLES = 5; // 最少需要5个样本

    /**
     * 内存泄漏统计
     */
    private final AtomicLong totalLeakDetections = new AtomicLong(0);
    private final AtomicLong totalLeakAlerts = new AtomicLong(0);
    private final AtomicReference<String> lastLeakReport = new AtomicReference<>("");

    /**
     * 内存泄漏检测 - 每1分钟执行一次
     */
    @Scheduled(fixedDelay = DETECTION_INTERVAL)
    public void detectMemoryLeaks() {
        try {
            // 记录当前内存快照
            MemorySnapshot currentSnapshot = captureMemorySnapshot();
            memoryHistory.put(System.currentTimeMillis(), currentSnapshot);
            
            // 清理历史记录
            cleanupMemoryHistory();
            
            // 检测内存泄漏
            if (memoryHistory.size() >= MIN_SAMPLES) {
                analyzeMemoryLeaks();
            }
            
        } catch (Exception e) {
            logger.error("内存泄漏检测异常", e);
            alertManager.sendSystemErrorAlert("内存泄漏检测异常", e.getMessage());
        }
    }

    /**
     * 捕获内存快照
     * 
     * @return 内存快照
     */
    private MemorySnapshot captureMemorySnapshot() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
            MemoryUsage nonHeapMemory = memoryBean.getNonHeapMemoryUsage();
            
            // 获取GC信息
            long totalGcCount = 0;
            long totalGcTime = 0;
            for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
                totalGcCount += gcBean.getCollectionCount();
                totalGcTime += gcBean.getCollectionTime();
            }
            
            return new MemorySnapshot(
                heapMemory.getUsed(),
                heapMemory.getMax(),
                nonHeapMemory.getUsed(),
                nonHeapMemory.getMax(),
                totalGcCount,
                totalGcTime,
                System.currentTimeMillis()
            );
            
        } catch (Exception e) {
            logger.error("捕获内存快照失败", e);
            return new MemorySnapshot(0, 0, 0, 0, 0, 0, System.currentTimeMillis());
        }
    }

    /**
     * 清理内存历史记录
     */
    private void cleanupMemoryHistory() {
        try {
            long currentTime = System.currentTimeMillis();
            long cutoffTime = currentTime - (HISTORY_SIZE * DETECTION_INTERVAL);
            
            memoryHistory.entrySet().removeIf(entry -> entry.getKey() < cutoffTime);
            
            logger.debug("内存历史记录清理完成，当前记录数: {}", memoryHistory.size());
            
        } catch (Exception e) {
            logger.error("清理内存历史记录失败", e);
        }
    }

    /**
     * 分析内存泄漏
     */
    private void analyzeMemoryLeaks() {
        try {
            // 获取最近的内存快照
            MemorySnapshot[] recentSnapshots = memoryHistory.values().stream()
                .sorted((a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()))
                .limit(MIN_SAMPLES)
                .toArray(MemorySnapshot[]::new);
            
            if (recentSnapshots.length < MIN_SAMPLES) {
                return;
            }
            
            // 分析堆内存趋势
            analyzeHeapMemoryTrend(recentSnapshots);
            
            // 分析非堆内存趋势
            analyzeNonHeapMemoryTrend(recentSnapshots);
            
            // 分析GC趋势
            analyzeGcTrend(recentSnapshots);
            
        } catch (Exception e) {
            logger.error("分析内存泄漏失败", e);
        }
    }

    /**
     * 分析堆内存趋势
     */
    private void analyzeHeapMemoryTrend(MemorySnapshot[] snapshots) {
        try {
            // 计算堆内存使用率趋势
            double[] heapUsageRates = new double[snapshots.length];
            for (int i = 0; i < snapshots.length; i++) {
                MemorySnapshot snapshot = snapshots[i];
                heapUsageRates[i] = snapshot.getMaxHeap() > 0 ? 
                    (double) snapshot.getUsedHeap() / snapshot.getMaxHeap() * 100 : 0;
            }
            
            // 计算趋势
            double trend = calculateTrend(heapUsageRates);
            
            if (trend > LEAK_THRESHOLD) {
                String message = String.format("检测到堆内存泄漏趋势: 增长率为 %.2f%%", trend);
                logger.warn(message);
                
                // 发送告警
                alertManager.sendMemoryLeakAlert("堆内存泄漏", message);
                totalLeakAlerts.incrementAndGet();
                
                // 记录泄漏报告
                lastLeakReport.set(message);
            }
            
            totalLeakDetections.incrementAndGet();
            
        } catch (Exception e) {
            logger.error("分析堆内存趋势失败", e);
        }
    }

    /**
     * 分析非堆内存趋势
     */
    private void analyzeNonHeapMemoryTrend(MemorySnapshot[] snapshots) {
        try {
            // 计算非堆内存使用率趋势
            double[] nonHeapUsageRates = new double[snapshots.length];
            for (int i = 0; i < snapshots.length; i++) {
                MemorySnapshot snapshot = snapshots[i];
                nonHeapUsageRates[i] = snapshot.getMaxNonHeap() > 0 ? 
                    (double) snapshot.getUsedNonHeap() / snapshot.getMaxNonHeap() * 100 : 0;
            }
            
            // 计算趋势
            double trend = calculateTrend(nonHeapUsageRates);
            
            if (trend > LEAK_THRESHOLD) {
                String message = String.format("检测到非堆内存泄漏趋势: 增长率为 %.2f%%", trend);
                logger.warn(message);
                
                // 发送告警
                alertManager.sendMemoryLeakAlert("非堆内存泄漏", message);
                totalLeakAlerts.incrementAndGet();
                
                // 记录泄漏报告
                lastLeakReport.set(message);
            }
            
        } catch (Exception e) {
            logger.error("分析非堆内存趋势失败", e);
        }
    }

    /**
     * 分析GC趋势
     */
    private void analyzeGcTrend(MemorySnapshot[] snapshots) {
        try {
            // 计算GC频率趋势
            long[] gcCounts = new long[snapshots.length];
            for (int i = 0; i < snapshots.length; i++) {
                gcCounts[i] = snapshots[i].getGcCount();
            }
            
            // 计算GC频率增长趋势
            double gcTrend = calculateTrend(gcCounts);
            
            if (gcTrend > LEAK_THRESHOLD) {
                String message = String.format("检测到GC频率异常增长: 增长率为 %.2f%%", gcTrend);
                logger.warn(message);
                
                // 发送告警
                alertManager.sendMemoryLeakAlert("GC频率异常", message);
                totalLeakAlerts.incrementAndGet();
                
                // 记录泄漏报告
                lastLeakReport.set(message);
            }
            
        } catch (Exception e) {
            logger.error("分析GC趋势失败", e);
        }
    }

    /**
     * 计算趋势
     * 
     * @param values 数值数组
     * @return 趋势值（百分比）
     */
    private double calculateTrend(double[] values) {
        if (values.length < 2) {
            return 0.0;
        }
        
        // 使用线性回归计算趋势
        double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;
        int n = values.length;
        
        for (int i = 0; i < n; i++) {
            sumX += i;
            sumY += values[i];
            sumXY += i * values[i];
            sumXX += i * i;
        }
        
        double slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
        double avgY = sumY / n;
        
        return avgY > 0 ? (slope / avgY) * 100 : 0;
    }

    /**
     * 计算趋势（长整型版本）
     * 
     * @param values 数值数组
     * @return 趋势值（百分比）
     */
    private double calculateTrend(long[] values) {
        if (values.length < 2) {
            return 0.0;
        }
        
        // 使用线性回归计算趋势
        double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;
        int n = values.length;
        
        for (int i = 0; i < n; i++) {
            sumX += i;
            sumY += values[i];
            sumXY += i * values[i];
            sumXX += i * i;
        }
        
        double slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
        double avgY = sumY / n;
        
        return avgY > 0 ? (slope / avgY) * 100 : 0;
    }

    /**
     * 获取内存泄漏检测统计
     * 
     * @return 检测统计
     */
    public MemoryLeakDetectionStatistics getDetectionStatistics() {
        return new MemoryLeakDetectionStatistics(
            totalLeakDetections.get(),
            totalLeakAlerts.get(),
            memoryHistory.size(),
            lastLeakReport.get(),
            System.currentTimeMillis()
        );
    }

    /**
     * 获取内存历史记录
     * 
     * @return 内存历史记录
     */
    public ConcurrentHashMap<Long, MemorySnapshot> getMemoryHistory() {
        return new ConcurrentHashMap<>(memoryHistory);
    }

    /**
     * 手动触发内存泄漏检测
     */
    public void triggerMemoryLeakDetection() {
        try {
            logger.info("手动触发内存泄漏检测");
            
            // 记录当前内存快照
            MemorySnapshot currentSnapshot = captureMemorySnapshot();
            memoryHistory.put(System.currentTimeMillis(), currentSnapshot);
            
            // 立即分析内存泄漏
            if (memoryHistory.size() >= MIN_SAMPLES) {
                analyzeMemoryLeaks();
            }
            
            logger.info("内存泄漏检测完成");
            
        } catch (Exception e) {
            logger.error("手动触发内存泄漏检测失败", e);
        }
    }

    /**
     * 内存快照类
     */
    public static class MemorySnapshot {
        private final long usedHeap;
        private final long maxHeap;
        private final long usedNonHeap;
        private final long maxNonHeap;
        private final long gcCount;
        private final long gcTime;
        private final long timestamp;

        public MemorySnapshot(long usedHeap, long maxHeap, long usedNonHeap, 
                            long maxNonHeap, long gcCount, long gcTime, long timestamp) {
            this.usedHeap = usedHeap;
            this.maxHeap = maxHeap;
            this.usedNonHeap = usedNonHeap;
            this.maxNonHeap = maxNonHeap;
            this.gcCount = gcCount;
            this.gcTime = gcTime;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getUsedHeap() { return usedHeap; }
        public long getMaxHeap() { return maxHeap; }
        public long getUsedNonHeap() { return usedNonHeap; }
        public long getMaxNonHeap() { return maxNonHeap; }
        public long getGcCount() { return gcCount; }
        public long getGcTime() { return gcTime; }
        public long getTimestamp() { return timestamp; }
        
        public double getHeapUsagePercent() { return maxHeap > 0 ? (double) usedHeap / maxHeap * 100 : 0; }
        public double getNonHeapUsagePercent() { return maxNonHeap > 0 ? (double) usedNonHeap / maxNonHeap * 100 : 0; }
    }

    /**
     * 内存泄漏检测统计类
     */
    public static class MemoryLeakDetectionStatistics {
        private final long totalDetections;
        private final long totalAlerts;
        private final int historySize;
        private final String lastLeakReport;
        private final long timestamp;

        public MemoryLeakDetectionStatistics(long totalDetections, long totalAlerts, 
                                           int historySize, String lastLeakReport, long timestamp) {
            this.totalDetections = totalDetections;
            this.totalAlerts = totalAlerts;
            this.historySize = historySize;
            this.lastLeakReport = lastLeakReport;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getTotalDetections() { return totalDetections; }
        public long getTotalAlerts() { return totalAlerts; }
        public int getHistorySize() { return historySize; }
        public String getLastLeakReport() { return lastLeakReport; }
        public long getTimestamp() { return timestamp; }
    }
}
